package com.aura.springbook.common;

import com.aura.springbook.common.exception.ResultCode;
import lombok.Data;

import java.io.Serializable;

/**
 * 通用响应结果封装类
 */
@Data
public class R<T> implements Serializable {

    /**
     * 状态码
     * <p>
     * 遵循HTTP状态码规范：
     * - 200开头：成功
     * - 400开头：客户端错误
     * - 500开头：服务器错误
     */
    private int code;

    /**
     * 提示信息
     * <p>
     * 用于向客户端传达操作结果的简要说明
     * 成功时通常为"操作成功"，失败时为具体的错误原因
     */
    private String message;

    /**
     * 响应数据
     * <p>
     * 成功时返回业务数据，失败时通常为null
     * 数据类型由泛型T指定
     */
    private T data;

    // 私有构造，避免直接实例化，通过静态方法创建
    private R() {
    }

    /**
     * 成功响应（无数据）
     * <p>
     * 创建不包含响应数据的成功响应对象
     *
     * @param <T> 数据类型
     * @return 响应对象
     */
    public static <T> R<T> ok() {
        return result(ResultCode.SUCCESS, null);
    }

    /**
     * 成功响应（带数据）
     * <p>
     * 创建包含响应数据的成功响应对象
     *
     * @param data 响应数据
     * @param <T>  数据类型
     * @return 响应对象
     */
    public static <T> R<T> ok(T data) {
        return result(ResultCode.SUCCESS, data);
    }

    /**
     * 失败响应（使用预定义的错误码）
     * <p>
     * 创建使用预定义错误码的失败响应对象
     *
     * @param code 错误码枚举
     * @param <T>  数据类型
     * @return 响应对象
     */
    public static <T> R<T> fail(ResultCode code) {
        return result(code, null);
    }

    /**
     * 失败响应（自定义消息，基于预定义错误码）
     * <p>
     * 创建使用预定义错误码和自定义消息的失败响应对象
     *
     * @param code 错误码枚举
     * @param msg  自定义错误消息
     * @param <T>  数据类型
     * @return 响应对象
     */
    public static <T> R<T> fail(ResultCode code, String msg) {
        R<T> r = new R<>();
        r.code = code.getCode();
        r.message = msg;
        r.data = null;
        return r;
    }

    /**
     * 内部工具方法：组装响应
     * <p>
     * 根据错误码和数据组装响应对象
     *
     * @param code 错误码枚举
     * @param data 响应数据
     * @param <T>  数据类型
     * @return 响应对象
     */
    private static <T> R<T> result(ResultCode code, T data) {
        R<T> r = new R<>();
        r.code = code.getCode();
        r.message = code.getMessage();
        r.data = data;
        return r;
    }
}